package actor

import java.io.File

import akka.actor.{Actor, ActorSystem, PoisonPill}
import akka.stream.Materializer
import command.{CommandExec, MissionUtils}
import dao._
import javax.inject.Inject
import models.Tables._
import org.apache.commons.io.FileUtils
import org.joda.time.DateTime
import play.api.libs.json.Json
import tool._
import utils.Utils

import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
import implicits.Implicits._
import shared.VarTool


/**
 * Created by Administrator on 2019/10/24
 */
class MissionExecActor @Inject()(mission: MissionRow)(implicit val system: ActorSystem,
                                                      implicit val materializer: Materializer,
                                                      implicit val missionDao: MissionDao,
                                                      implicit val modeDao: ModeDao,
) extends Actor {

  def crispr(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.crispr(workspaceDir, resultDir)
    }
  }

  def vfdb(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.vfdb(workspaceDir, resultDir)
    }.map { b =>
      Tool.vfdbResultDeal(workspaceDir, resultDir)
    }
  }

  def phi(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.phi(workspaceDir, resultDir)
    }.map { b =>
      Tool.phiResultDeal(workspaceDir, resultDir)
    }
  }

  def tcdb(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.tcdb(workspaceDir, resultDir)
    }.map { b =>
      Tool.tcdbResultDeal(workspaceDir, resultDir)
    }
  }

  def anno(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
        Tool.faGenePredicts2Pep(workspaceDir)
      }
      .exec { b =>
      Tool.anno(workspaceDir, resultDir)
    }.map { b =>
      Tool.annoResultDeal(workspaceDir, resultDir)
    }
  }

  def pfam(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.faGenePredicts2Pep(workspaceDir)
    }.exec { b =>
      Tool.pepPfam(workspaceDir, resultDir)
    }.map { b =>
      Tool.pfamResultDeal(workspaceDir, resultDir)
    }
  }

  def assemble(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.assemble(workspaceDir, resultDir)
    }
  }

  def assemblePredict(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.assemble(workspaceDir, resultDir)
    }.exec { b =>
      Tool.predictForAssemble(workspaceDir, resultDir)
    }.map { b =>
      Tool.assemblePredictResultDeal(workspaceDir, resultDir)
    }
  }

  def predict(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.predict(workspaceDir, resultDir)
    }
  }

  def ardb(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.ardb(workspaceDir, resultDir)
    }
  }

  def cazy(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
        Tool.faGenePredicts2Pep(workspaceDir)
      }
      .exec { b =>
      Tool.faCazy(workspaceDir, resultDir)
    }.map { b =>
      Tool.cazyResultDeal(workspaceDir, resultDir)
    }
  }

  def mummer(workspaceDir: File, resultDir: File)(implicit modeDao: ModeDao) = {
    CommandExec()
      .exec { b =>
      Tool.faGenePredicts(workspaceDir)
    }
      .exec { b =>
      Tool.faMummer(workspaceDir, resultDir)
    }.map { b =>
      Tool.mummerResultDeal(workspaceDir, resultDir)
    }
  }

  def orthoMcl(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.faGenePredict2Peps(workspaceDir)
    }.exec { b =>
      Tool.orthoMcl(workspaceDir, resultDir)
    }
  }

  def phyTree(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.faPhyTree(workspaceDir, resultDir)
    }
  }


  override def receive: Receive = {
    case "run" =>
      val newMision = mission.copy(state = "running")
      val userId = mission.userId
      val outDir = Tool.getUserMissionDir(mission.userId)
      val missionDir = MissionUtils.getMissionDir(mission.id, outDir)
      val (workspaceDir, resultDir) = (missionDir.workspaceDir, missionDir.resultDir)
      val logFile = Tool.getLogFile(workspaceDir.getParentFile)
      val configFile = new File(workspaceDir, "config.txt")
      val configJson = Json.parse(configFile.str)
      missionDao.update(newMision).map { x =>
        val commandExec = mission.kind match {
          case VarTool.mummerStr => mummer(workspaceDir, resultDir)
          case VarTool.orthoMclStr => orthoMcl(workspaceDir, resultDir)
          case VarTool.phyTreeStr => phyTree(workspaceDir, resultDir)
          case VarTool.crisprStr => crispr(workspaceDir, resultDir)
          case VarTool.vfdbStr => vfdb(workspaceDir, resultDir)
          case VarTool.ardbStr => ardb(workspaceDir, resultDir)
          case VarTool.cazyStr => cazy(workspaceDir, resultDir)
          case VarTool.phiStr => phi(workspaceDir, resultDir)
          case VarTool.tcdbStr => tcdb(workspaceDir, resultDir)
          case VarTool.annoStr => anno(workspaceDir, resultDir)
          case VarTool.pfamStr => pfam(workspaceDir, resultDir)
          case VarTool.assembleStr => assemble(workspaceDir, resultDir)
          case VarTool.predictStr => predict(workspaceDir, resultDir)
          case VarTool.assemblePredictStr => assemblePredict(workspaceDir, resultDir)
        }
        val state = if (commandExec.isSuccess) {
          "success"
        } else {
          commandExec.errorInfo.toFile(logFile)
          "error"
        }
        val newMission = mission.copy(state = state, endTime = Some(new DateTime()))
        missionDao.update(newMission).map { x =>
        }
      }.onComplete {
        case Failure(exception) =>
          exception.printStackTrace()
          FileUtils.writeStringToFile(logFile, exception.toString)
          val newMission = mission.copy(state = "error", endTime = Some(new DateTime()))
          missionDao.update(newMission).map { x =>
          }
          self ! "stop"
        case Success(x) =>
          self ! "stop"
      }

    case "stop" =>
      self ! PoisonPill

  }
}
